﻿namespace WPCloudAppIteration2.Phone.ViewModel
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Globalization;
    using System.IO;
    using System.Windows;
    using System.Windows.Threading;
    using Microsoft.Phone.Tasks;
    using Microsoft.Samples.WindowsPhoneCloud.StorageClient;

    public class UploadPhotoPageViewModel : BaseViewModel
    {
        private readonly ICloudBlobClient blobClient;
        private readonly Dispatcher dispatcher;

        private string containerName;
        private string blobName;
        private Uri path;
        private bool isUploading;
        private bool isPublic;
        private bool includeLocationData;
        private bool includeAuthorData;
        private ObservableCollection<string> containerNames = new ObservableCollection<string>();

        public UploadPhotoPageViewModel()
            : this(App.CloudClientFactory.ResolveCloudBlobClient("UploadAndList"), Deployment.Current.Dispatcher)
        {
        }

        public UploadPhotoPageViewModel(ICloudBlobClient blobClient, Dispatcher dispatcher)
        {
            this.blobClient = blobClient;
            this.dispatcher = dispatcher;

            this.blobClient.ListContainers(
                r =>
                {
                    if (this.dispatcher != null)
                    {
                        this.dispatcher.BeginInvoke(() => this.UpdateListBlobs(r));
                    }
                    else
                    {
                        this.UpdateListBlobs(r);
                    }
                });
        }

        public string BlobName
        {
            get
            {
                return this.blobName;
            }

            set
            {
                if (this.blobName != value)
                {
                    this.blobName = value;
                    this.NotifyPropertyChanged("BlobName");
                }
            }
        }

        public string ContainerName
        {
            get
            {
                return this.containerName;
            }

            set
            {
                if (this.containerName != value)
                {
                    this.containerName = value;
                    this.NotifyPropertyChanged("ContainerName");
                }
            }
        }

        public Uri Path
        {
            get
            {
                return this.path;
            }

            set
            {
                if (this.path != value)
                {
                    this.path = value;
                    this.NotifyPropertyChanged("Path");
                }
            }
        }

        public bool IsUploading
        {
            get
            {
                return this.isUploading;
            }

            set
            {
                if (this.isUploading != value)
                {
                    this.isUploading = value;
                    this.NotifyPropertyChanged("IsUploading");
                }
            }
        }

        public bool IsPublic
        {
            get
            {
                return this.isPublic;
            }

            set
            {
                if (this.isPublic != value)
                {
                    this.isPublic = value;
                    this.NotifyPropertyChanged("IsPublic");
                }
            }
        }

        public bool IncludeLocationData
        {
            get
            {
                return this.includeLocationData;
            }

            set
            {
                if (this.includeLocationData != value)
                {
                    this.includeLocationData = value;
                    this.NotifyPropertyChanged("IncludeLocationData");
                }
            }
        }

        public bool IncludeAuthorData
        {
            get
            {
                return this.includeAuthorData;
            }

            set
            {
                if (this.includeAuthorData != value)
                {
                    this.includeAuthorData = value;
                    this.NotifyPropertyChanged("IncludeAuthorData");
                }
            }
        }

        public ObservableCollection<string> ContainerNames
        {
            get
            {
                return this.containerNames;
            }

            set
            {
                if (this.containerNames != value)
                {
                    this.containerNames = value;
                    this.NotifyPropertyChanged("ContainerNames");
                }
            }
        }

        public Stream PhotoStream { get; set; }

        public void LoadPhoto(PhotoResult photoResult)
        {
            this.Path = new Uri(photoResult.OriginalFileName);
            this.BlobName = string.Format(
                CultureInfo.InvariantCulture,
                "Capture-{0}{1}",
                DateTime.Now.ToString("yyyyMMddTHHmmss", CultureInfo.InvariantCulture),
                System.IO.Path.GetExtension(photoResult.OriginalFileName));
            this.PhotoStream = photoResult.ChosenPhoto;

            this.ContainerName = "pictures";
        }

        public void UploadPhoto(string latitude, string longitude, string userIdentifier, Action<string> successCallback, Action<string> failureCallback)
        {
            this.IsUploading = true;

            /*
             * Pseudo code:
             * var container = this.blobClient.GetContainerReference(this.ContainerName);
             * container.CreateIfNotExist();
             * 
             * var blob = container.GetBlobReference(this.BlobName);
             * blob.UploadFromStream(this.PhotoStream);
             */
            var container = this.blobClient.GetContainerReference(this.ContainerName);
            container.CreateIfNotExist(
                this.IsPublic,
                r => this.dispatcher.BeginInvoke(
                () =>
                {
                    // Successfull container creation.
                    if (r.Exception == null)
                    {
                        var blob = container.GetBlobReference(this.BlobName);

                        if (this.IncludeLocationData)
                        {
                            blob.Metadata["ContentLocation"] = string.Concat("http://www.bing.com/maps/?v=2&cp=", latitude, "~", longitude, "&lvl=16&dir=0&sty=h");
                        }

                        if (this.IncludeAuthorData && !string.IsNullOrWhiteSpace(userIdentifier))
                        {
                            blob.Metadata["ContentAuthor"] = userIdentifier;
                        }

                        blob.Metadata["ImageType"] = "image/jpeg";

                        blob.UploadFromStream(
                            this.PhotoStream,
                            response => this.dispatcher.BeginInvoke(
                            () =>
                            {
                                this.IsUploading = false;

                                if (response.Exception == null)
                                {
                                    if (successCallback != null)
                                    {
                                        successCallback(string.Format(CultureInfo.InvariantCulture, "Image file {0} successfully uploaded!", this.BlobName));
                                    }
                                }
                                else
                                {
                                    if (failureCallback != null)
                                    {
                                        failureCallback(string.Format(CultureInfo.InvariantCulture, "Error: {0}", response.Exception.Message));
                                    }
                                }
                            }));
                    }
                    else
                    {
                        this.IsUploading = false;

                        // The container was not created successfully, some error has ocurred.
                        if (failureCallback != null)
                        {
                            failureCallback(string.Format(CultureInfo.InvariantCulture, "Error: {0}", r.Exception.Message));
                        }
                    }
                }));
        }

        private void UpdateListBlobs(CloudOperationResponse<IEnumerable<ICloudBlobContainer>> result)
        {
            if (result.Exception == null)
            {
                if (this.ContainerNames != null)
                {
                    this.ContainerNames.Clear();
                }

                foreach (var container in result.Response)
                {
                    this.ContainerNames.Add(container.Name);
                }
            }
        }
    }
}
